home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / system / ms_sh22b.zip / src / director.c next >
C/C++ Source or Header  |  1993-12-01  |  9KB  |  486 lines

  1. /*
  2.  * @(#)msd_dir.c 1.4 87/11/06    Public Domain.
  3.  *
  4.  *  A public domain implementation of BSD directory routines for
  5.  *  MS-DOS.  Written by Michael Rendell ({uunet,utai}michael@garfield),
  6.  *  August 1897
  7.  *
  8.  *  Modified by Ian Stewartson, Data Logic (istewart@datlog.co.uk).
  9.  *
  10.  *  Updates:  1.  To support OS/2 1.x
  11.  *          2.  To support HPFS long filenames
  12.  *          3.  To support OS/2 2.x
  13.  *          4.  To support TurboC
  14.  */
  15.  
  16. #include <sys/types.h>
  17. #include <sys/stat.h>
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20.  
  21. #ifndef __TURBOC__
  22. #  include <malloc.h>
  23. #endif
  24.  
  25. #include <string.h>
  26. #include <limits.h>
  27. #include <ctype.h>
  28. #include <errno.h>
  29. #include <dirent.h>
  30.  
  31. #ifdef __TURBOC__
  32. #  include <dir.h>
  33. #endif
  34.  
  35. #if defined (OS2) || defined (__OS2__)
  36. #  define INCL_DOSFILEMGR
  37. #  define INCL_DOSMISC
  38. #  include <os2.h>
  39.  
  40. #  if defined (__OS2__)
  41. #    define DISABLE_HARD_ERRORS    DosError (FERR_DISABLEHARDERR)
  42. #    define ENABLE_HARD_ERRORS    DosError (FERR_ENABLEHARDERR)
  43. #  else
  44. #    define DISABLE_HARD_ERRORS    DosError (HARDERROR_DISABLE)
  45. #    define ENABLE_HARD_ERRORS    DosError (HARDERROR_ENABLE)
  46. #  endif
  47.  
  48. #else
  49. #  include <dos.h>
  50. #  define DISABLE_HARD_ERRORS
  51. #  define ENABLE_HARD_ERRORS
  52. #endif
  53.  
  54. #if defined (OS2) || defined (__OS2__)
  55. #  define ATTRIBUTES        (FILE_DIRECTORY | FILE_HIDDEN | FILE_SYSTEM | \
  56.                  FILE_NORMAL | FILE_READONLY | FILE_ARCHIVED)
  57. #elif defined (__TURBOC__)
  58. #  define ATTRIBUTES        (FA_RDONLY | FA_HIDDEN | FA_SYSTEM | \
  59.                  FA_DIREC | FA_ARCH)
  60. #else
  61. #  define ATTRIBUTES        (_A_SUBDIR | _A_HIDDEN | _A_SYSTEM | \
  62.                  _A_NORMAL | _A_RDONLY | _A_ARCH)
  63. #endif
  64.  
  65. /*
  66.  * OS/2 2.x has these missing
  67.  */
  68.  
  69. #ifndef ENOTDIR
  70. #  define ENOTDIR    120    /* Not a directory            */
  71. #endif
  72.  
  73. #ifndef S_IFMT
  74. #  define    S_IFMT    0xf000    /* type of file                */
  75. #endif
  76.  
  77. #ifndef S_ISDIR
  78. #  define S_ISDIR(m)    ((((m) & S_IFMT) == S_IFDIR))
  79. #endif
  80.  
  81. /*
  82.  * Internals
  83.  */
  84.  
  85. typedef struct _dircontents    DIRCONT;
  86. static void            free_dircontents (DIRCONT *);
  87.  
  88. /*
  89.  * Open the directory stream
  90.  */
  91.  
  92. DIR        *opendir (name)
  93. const char    *name;
  94. {
  95.     struct stat        statb;
  96.     DIR            *dirp;
  97.     char        *last;
  98.     DIRCONT        *dp;
  99.     char        *nbuf;
  100. #if defined (__OS2__)
  101.     FILEFINDBUF3     dtabuf;
  102.     HDIR        d_handle = HDIR_SYSTEM;
  103.     ULONG        d_count = 1;
  104.     bool        HPFS = FALSE;
  105. #elif defined (OS2)
  106.     FILEFINDBUF     dtabuf;
  107.     HDIR        d_handle = HDIR_SYSTEM;
  108.     USHORT        d_count = 1;
  109.     bool        HPFS = FALSE;
  110. #elif defined (__TURBOC__)
  111.     struct ffblk    dtabuf;
  112. #else
  113.     struct find_t    dtabuf;
  114. #endif
  115.     int            len = strlen (name);
  116.     unsigned long    rc;
  117.  
  118.     if (!len)
  119.     {
  120.     errno = ENOTDIR;
  121.     return (DIR *)NULL;
  122.     }
  123.  
  124.     if ((nbuf = malloc (len + 5)) == (char *)NULL)
  125.     return (DIR *) NULL;
  126.  
  127.     strcpy (nbuf, name);
  128.     last = &nbuf[len - 1];
  129.  
  130. /* Ok, DOS is very picky about its directory names.  The following are
  131.  * valid.
  132.  *
  133.  *  c:/
  134.  *  c:.
  135.  *  c:name/name1
  136.  *
  137.  *  c:name/ is not valid
  138.  */
  139.  
  140.     if (((*last == '\\') || (*last == '/')) && (len > 1) &&
  141.     (!((len == 3) && (name[1] == ':'))))
  142.     *(last--) = 0;
  143.  
  144. /* Check its a directory */
  145.  
  146.     DISABLE_HARD_ERRORS;
  147.     rc = stat (nbuf, &statb);
  148.     ENABLE_HARD_ERRORS;
  149.  
  150.     if (rc)
  151.     {
  152.     free (nbuf);
  153.     return (DIR *) NULL;
  154.     }
  155.  
  156.     if (!S_ISDIR (statb.st_mode))
  157.     {
  158.     free (nbuf);
  159.     errno = ENOTDIR;
  160.     return (DIR *)NULL;
  161.     }
  162.  
  163.     if ((dirp = (DIR *) malloc (sizeof (DIR))) == (DIR *) NULL)
  164.     {
  165.     free (nbuf);
  166.     return (DIR *) NULL;
  167.     }
  168.  
  169. /* Set up to find everything */
  170.  
  171.     if ((*last != '\\') && (*last != '/'))
  172.     strcat (last, "/");
  173.  
  174.     strcat (last, "*.*");
  175.  
  176. /* For OS/2, find the file system type */
  177.  
  178. #if defined (OS2) || defined (__OS2__)
  179.     HPFS = IsHPFSFileSystem (nbuf);
  180. #endif
  181.  
  182.     dirp->dd_loc      = 0;
  183.     dirp->dd_cp       = (DIRCONT *) NULL;
  184.     dirp->dd_contents = (DIRCONT *) NULL;
  185.  
  186.     DISABLE_HARD_ERRORS;
  187.  
  188. #  if defined (__OS2__)
  189.     rc = DosFindFirst (nbuf, &d_handle, ATTRIBUTES, &dtabuf,
  190.                sizeof (FILEFINDBUF3), &d_count, FIL_STANDARD);
  191. #  elif defined (OS2)
  192.     rc = DosFindFirst (nbuf, &d_handle, ATTRIBUTES, &dtabuf,
  193.                sizeof (FILEFINDBUF), &d_count, (ULONG)0);
  194. #elif defined (__TURBOC__)
  195.     rc = findfirst (nbuf, &dtabuf, ATTRIBUTES);
  196. #else
  197.     rc = _dos_findfirst (nbuf, ATTRIBUTES, &dtabuf);
  198. #endif
  199.  
  200.     ENABLE_HARD_ERRORS;
  201.  
  202.     if (rc)
  203.     {
  204.     free (nbuf);
  205.     free (dirp);
  206.     return (DIR *) NULL;
  207.     }
  208.  
  209.     do
  210.     {
  211. #if defined (OS2) || defined (__OS2__)
  212.     if (((dp = (DIRCONT *) malloc (sizeof (DIRCONT))) == (DIRCONT *)NULL) ||
  213.         ((dp->_d_entry = strdup (dtabuf.achName)) == (char *) NULL))
  214. #elif defined (__TURBOC__)
  215.     if (((dp = (DIRCONT *) malloc (sizeof (DIRCONT))) == (DIRCONT *)NULL) ||
  216.         ((dp->_d_entry = strdup (dtabuf.ff_name)) == (char *) NULL))
  217. #else
  218.     if (((dp = (DIRCONT *) malloc (sizeof (DIRCONT))) == (DIRCONT *)NULL) ||
  219.         ((dp->_d_entry = strdup (dtabuf.name)) == (char *) NULL))
  220. #endif
  221.     {
  222.         if (dp->_d_entry != (char *)NULL)
  223.         free ((char *)dp);
  224.  
  225.         free (nbuf);
  226.         free_dircontents (dirp->dd_contents);
  227.  
  228. #if defined (OS2) || defined (__OS2__)
  229.         DosFindClose (d_handle);
  230. #endif
  231.         return (DIR *) NULL;
  232.     }
  233.  
  234. #if defined (OS2) || defined (__OS2__)
  235.     if (!HPFS)
  236.         strlwr (dp->_d_entry);
  237. #else
  238.     strlwr (dp->_d_entry);
  239. #endif
  240.  
  241.     if (dirp->dd_contents != (DIRCONT *) NULL)
  242.         dirp->dd_cp = dirp->dd_cp->_d_next = dp;
  243.  
  244.     else
  245.         dirp->dd_contents = dirp->dd_cp = dp;
  246.  
  247.     dp->_d_next = (DIRCONT *) NULL;
  248.  
  249. #if defined (OS2) || defined (__OS2__)
  250.     d_count = 1;
  251.     } while (DosFindNext (d_handle, &dtabuf, sizeof (FILEFINDBUF),
  252.               &d_count) == 0);
  253. #elif defined (__TURBOC__)
  254.     } while (findnext (&dtabuf) == 0);
  255. #else
  256.     } while (_dos_findnext (&dtabuf) == 0);
  257. #endif
  258.  
  259.     dirp->dd_cp = dirp->dd_contents;
  260.     free (nbuf);
  261.  
  262. #if defined (OS2) || defined (__OS2__)
  263.     DosFindClose (d_handle);
  264. #endif
  265.  
  266.     return dirp;
  267. }
  268.  
  269.  
  270. /*
  271.  * Close the directory stream
  272.  */
  273.  
  274. int    closedir (dirp)
  275. DIR    *dirp;
  276. {
  277.     if (dirp != (DIR *)NULL)
  278.     {
  279.     free_dircontents (dirp->dd_contents);
  280.     free ((char *)dirp);
  281.     }
  282.  
  283.     return 0;
  284. }
  285.  
  286. /*
  287.  * Read the next record from the stream
  288.  */
  289.  
  290. struct dirent    *readdir (dirp)
  291. DIR        *dirp;
  292. {
  293.     static struct dirent    dp;
  294.  
  295.     if ((dirp == (DIR *)NULL) || (dirp->dd_cp == (DIRCONT *) NULL))
  296.     return (struct dirent *) NULL;
  297.  
  298.     dp.d_reclen = strlen (strcpy (dp.d_name, dirp->dd_cp->_d_entry));
  299.     dp.d_off    = dirp->dd_loc * 32;
  300.     dp.d_ino    = (ino_t)++dirp->dd_loc;
  301.     dirp->dd_cp = dirp->dd_cp->_d_next;
  302.  
  303.     return &dp;
  304. }
  305.  
  306. /*
  307.  * Restart the directory stream
  308.  */
  309.  
  310. void    rewinddir (dirp)
  311. DIR    *dirp;
  312. {
  313.     seekdir (dirp, (off_t)0);
  314. }
  315.  
  316. /*
  317.  * Move to a know position in the stream
  318.  */
  319.  
  320. void    seekdir (dirp, off)
  321. DIR    *dirp;
  322. off_t    off;
  323. {
  324.     long    i = off;
  325.     DIRCONT    *dp;
  326.  
  327.     if ((dirp == (DIR *)NULL) || (off < 0L))
  328.     return;
  329.  
  330.     for (dp = dirp->dd_contents; (--i >= 0) && (dp != (DIRCONT *)NULL);
  331.      dp = dp->_d_next)
  332.     ;
  333.  
  334.     dirp->dd_loc = off - (i + 1);
  335.     dirp->dd_cp = dp;
  336. }
  337.  
  338. /*
  339.  * Get the current position
  340.  */
  341.  
  342. off_t    telldir(dirp)
  343. DIR    *dirp;
  344. {
  345.     return (dirp == (DIR *)NULL) ? (off_t) -1 : dirp->dd_loc;
  346. }
  347.  
  348. /*
  349.  * Release the internal structure
  350.  */
  351.  
  352. static void    free_dircontents (dp)
  353. DIRCONT        *dp;
  354. {
  355.     DIRCONT    *odp;
  356.  
  357.     while ((odp = dp) != (DIRCONT *)NULL)
  358.     {
  359.     if (dp->_d_entry != (char *)NULL)
  360.         free (dp->_d_entry);
  361.  
  362.     dp = dp->_d_next;
  363.     free ((char *)odp);
  364.     }
  365. }
  366.  
  367. /*
  368.  * For OS/2, we need to know if we have to convert to lower case.  This
  369.  * only applies to non-HPFS (FAT, NETWARE etc) file systems.
  370.  */
  371.  
  372. #if defined (OS2) || defined (__OS2__)
  373.  
  374. /*
  375.  * Define the know FAT systems
  376.  */
  377.  
  378. static char    *FATSystems[] = {"FAT", "NETWARE", (char *)NULL};
  379.  
  380. /*
  381.  * Check for Long filenames
  382.  */
  383.  
  384. bool        IsHPFSFileSystem (char *directory)
  385. {
  386.     ULONG        lMap;
  387.     BYTE        bData[128];
  388.     BYTE        bName[3];
  389.     int            i;
  390.     char        *FName;
  391.     unsigned long    rc;
  392. #if defined (__OS2__)
  393.     ULONG        cbData;
  394.     ULONG        nDrive;
  395.     PFSQBUFFER2        pFSQ = (PFSQBUFFER2)bData;
  396. #else
  397.     USHORT        cbData;
  398.     USHORT        nDrive;
  399. #endif
  400.  
  401.     if ( _osmode == DOS_MODE )
  402.     return FALSE;
  403.  
  404. /*
  405.  * Mike tells me there are IFS calls to determine this, but he carn't
  406.  * remember which.  So we read the partition info and check for HPFS.
  407.  */
  408.  
  409.     if (isalpha (directory[0]) && (directory[1] == ':'))
  410.     nDrive = toupper (directory[0]) - '@';
  411.  
  412.     else
  413.     DosQCurDisk (&nDrive, &lMap);
  414.  
  415. /* Set up the drive name */
  416.  
  417.     bName[0]